﻿// ## 2023/11/21 # 铃 #完全汉化,添加注释,整理代码,优化语句, ##
// ## 2023/03/21 # 铃 # 对撤退状态的战斗部队做了例外排除, ##
// ## 2021/10/10 # 江东新风 # warning修复 ##
// ## 2021/10/04 # 江东新风 # 部队任务_收复改为修复 ##
// ## 2020/11/17 # 江东新风 # trace 信息乱码修复 ##
// ## 2020/10/31 # 江东新风 # 同步马术书大神的更新，本地化##
/*
// 작성자: 기마책사
// Update: '20.10.24    / 최초내용 : 노병/간접병기부대 근접교전 회피기동 추가, 공성전 공성부대 좌표확보 기동 추가
// Update: '20.10.30    / 수정내용 : 공성기동 일반부대 확인조건 오류수정

*/

namespace AI优化_战斗部队移动
{

    //=======================================================================================

    // 在战斗中，避开与敌方部队接近的位置进行回避移动
    const bool 间接兵器_回避行动 = true;
    const bool 冲车部队_回避行动 = true;
    // 在攻城战中，优化部队的移动
    const int 据点进攻_活动部队数 = 3;   // 设定攻击据点时使用的攻城兵器部队数量(每回合/据点，最少=1~最多=5)
    const bool 攻城部队_优先行动 = true; // 当据点周围有攻城兵器部队(冲车/木兽/井阑/投石)时，它们会优先进行移动和攻城行动
    //=======================================================================================
    const bool 调试模式 = false;
    class Main
    {

        Main()
        {
            //pk::bind(111, pk::trigger111_t(onTurnStart));//---此函数会导致部队二动
        }
        //---------------------------------------------------------------------------------------

        // AI势力脚本(马术书强调注明:回合开始时，而不是261函数)
        void onTurnStart(pk::force @force)
        {
            int force_id = force.get_id();
            if (!pk::is_campaign())
            {
                if (pk::is_normal_force(force_id) and !force.is_player())
                {

                    for (int j = 0; j < 据点_末; j++)
                    {
                        pk::building @dst_base = pk::get_building(j);
                        if (pk::enemies_around(dst_base) and pk::is_enemy(dst_base, force))
                        {
                            func_siege_formation(dst_base, force);
                            if (攻城部队_优先行动)
                                func_siege_prior_atk(dst_base, force);
                        }
                    }

                    // 回避机动脚本
                    if (冲车部队_回避行动 or 间接兵器_回避行动)
                    {
                        pk::array<pk::unit @> arr_unit_force = pk::list_to_array(pk::get_unit_list(force));
                        if (冲车部队_回避行动)
                        {
                            for (int i = 0; i < int(arr_unit_force.length); i++)
                                func_siegeram_evasion(arr_unit_force[i]);
                        }
                        if (间接兵器_回避行动)
                        {
                            for (int i = 0; i < int(arr_unit_force.length); i++)
                                func_archer_evasion(arr_unit_force[i]);
                        }
                    }
                }
            }
        }

        // 这是一个判断武器类型的函数，用于确认兵种属性
        bool is_dir_weapon(int weapon_id) { return ((兵器_剑 <= weapon_id and weapon_id <= 兵器_战马) and weapon_id != 兵器_弩); }
        bool is_siege_weapon(int weapon_id) { return (兵器_冲车 <= weapon_id and weapon_id <= 兵器_木兽); }
        bool is_siegeram_weapon(int weapon_id) { return (兵器_冲车 == weapon_id or weapon_id == 兵器_木兽); }
        bool is_siegerng_weapon(int weapon_id) { return (兵器_井阑 == weapon_id or weapon_id == 兵器_投石); }
        bool is_ship_weapon(int weapon_id) { return (weapon_id == 兵器_楼船 or weapon_id == 兵器_斗舰); }
        //=======================================================================================
        // 间接兵器部队回避机动（弩兵，投石，火器），冲车部队回避机动（冲车）
        //---------------------------------------------------------------------------------------
        // 执行间接兵器部队回避机动函数
        void func_archer_evasion(pk::unit @unit)
        {
            if (!check_valid_evasion_unit(unit))
                return;
            if (unit.weapon >= 兵器_走舸 or unit.weapon == 兵器_战马)
                return; // 排除水军和骑兵

            if (unit.status != 部队状态_通常)
                return;

            pk::unit @enemy = get_neighbor_enemy_unit(unit);
            if (!pk::is_alive(enemy))
                return; // 没有接触到周围的敌军部队
            int max_range = get_atk_range(unit).second;
            if (max_range <= 1)
                return; // 不是间接兵器部队
            // 如果是间接攻城武器，检查移动范围内是否有可攻城的据点
            if (is_siegerng_weapon(unit.weapon))
            {
                pk::building @target_base = get_siege_target_base(unit);
                if (pk::is_alive(target_base))
                {
                    atk_target_base(unit, target_base);
                    return;
                }
            }
            pk::point prev_pos = unit.pos;
            pk::point evasion_pos = get_evasion_pos(unit, max_range); // 搜索回避机动候选坐标（在最大射程内）
            if (evasion_pos == -1 or !pk::is_valid_pos(evasion_pos))
                evasion_pos = get_evasion_pos(unit, max_range + 2); // 重新搜索回避机动候选坐标（在最大射程外）
            if (evasion_pos == -1 or !pk::is_valid_pos(evasion_pos))
                return; // 如果没有有效坐标，则无法进行回避机动
            bool is_moved = unit_movement_control(unit, evasion_pos, /*is_func262*/ false);
            if (!is_moved)
                return;
            run_order_combat_unit(prev_pos, unit, enemy, 3);
        }
        //---------------------------------------------------------------------------------------
        // 执行冲车部队回避机动函数
        void func_siegeram_evasion(pk::unit @unit)
        {
            if (!check_valid_evasion_unit(unit))
                return;
            if (unit.weapon != 兵器_冲车)
                return; // 仅针对冲车
            pk::unit @enemy = get_neighbor_enemy_unit(unit);
            if (!pk::is_alive(enemy))
                return; // 没有接触到周围的敌军部队
            // 检查移动范围内是否有可攻城的据点
            pk::building @target_base = get_siege_target_base(unit);
            if (pk::is_alive(target_base))
            {
                atk_target_base(unit, target_base);
                return;
            }
            int max_range = 5;
            pk::point prev_pos = unit.pos;
            pk::point evasion_pos = get_evasion_pos(unit, max_range); // 搜索回避机动候选坐标（最大5格外）
            if (evasion_pos == -1 or !pk::is_valid_pos(evasion_pos))
                return;
            bool is_moved = unit_movement_control(unit, evasion_pos, /*is_func262*/ false);
            if (!is_moved)
                return;
            run_order_combat_unit(prev_pos, unit, enemy, 3);
        }
        //---------------------------------------------------------------------------------------
        // 检查是否为有效的回避单位
        bool check_valid_evasion_unit(pk::unit @unit)
        {
            if (!pk::is_alive(unit))
                return false;
            if (unit.action_done)
                return false; // 如果单位已经行动完毕，则返回false
            if (unit.order == 部队任务_撤退)
                return false;
            if (unit.status != 部队状态_通常)
                return false; // 如果单位状态不是正常状态，则返回false
            if (pk::is_player_controlled(unit))
                return false;
            return true;
        }
        //---------------------------------------------------------------------------------------
        // 攻击目标为据点的函数
        void atk_target_base(pk::unit @unit, pk::building @target_base)
        {
            // 撤退部队无效
            if (unit.order == 部队任务_撤退)
                return;
            pk::set_order(unit, 部队任务_攻击, target_base.pos);
            pk::run_order(unit);
            unit.action_done = true;
        }
        //---------------------------------------------------------------------------------------
        // 执行周围普通战斗单位的命令
        void run_order_combat_unit(pk::point prev_pos, pk::unit @unit, pk::unit @enemy, int range)
        {
            pk::list<pk::unit @> list_unit_combat_evasion;
            pk::array<pk::point> arr_range = pk::range(prev_pos, 1, range);
            for (int i = 0; i < int(arr_range.length); i++)
            {
                pk::point pos_t = arr_range[i];
                pk::unit @unit_atk = pk::get_unit(pos_t);
                if (pk::is_alive(unit_atk) and !unit_atk.action_done and is_dir_weapon(unit_atk.weapon) and unit_atk.get_id() != unit.get_id() and unit_atk.get_force_id() == unit.get_force_id() and !pk::is_player_controlled(unit_atk) and unit_atk.target_type == 部队任务对象_部队)
                {
                    pk::unit @target = pk::get_unit(unit_atk.target);
                    if (pk::is_alive(target) and target.get_id() == enemy.get_id() and pk::is_enemy(target, unit_atk) and !list_unit_combat_evasion.contains(unit_atk))
                        list_unit_combat_evasion.add(unit_atk);
                }
            }
            if (list_unit_combat_evasion.count == 0)
                return;
            list_unit_combat_evasion.sort(function(a, b) {
                return ((a.attr.stat[部队能力_攻击] + a.attr.stat[部队能力_防御]) > (b.attr.stat[部队能力_攻击] + b.attr.stat[部队能力_防御]));
            });
            pk::unit @unit_combat = list_unit_combat_evasion[0];
            if (!unit_combat.action_done)
            {
                pk::run_order(unit_combat);
                unit_combat.action_done = true;
            }
        }
        //---------------------------------------------------------------------------------------
        // 获取周围敌军单位的函数
        pk::unit @get_neighbor_enemy_unit(pk::unit @unit)
        {
            for (int i = 0; i < 方向_末; i++)
            {
                pk::point neighbor_pos = pk::get_neighbor_pos(unit.pos, i);
                if (pk::is_valid_pos(neighbor_pos))
                {
                    pk::unit @unit_t = pk::get_unit(neighbor_pos);
                    if (pk::is_alive(unit_t) and unit_t.get_id() != unit.get_id() and pk::is_enemy(unit, unit_t) and is_dir_weapon(unit_t.weapon))
                        return unit_t;
                }
            }
            return null;
        }
        //---------------------------------------------------------------------------------------
        // 获取回避位置的函数
        pk::unit @unit_temp;
        int unit_max_range;
        pk::point get_evasion_pos(pk::unit @unit, int range = 1)
        {
            @unit_temp = unit;
            unit_max_range = range;
            pk::array<pk::point> arr_evasion_pos;
            pk::array<pk::point> arr_range = pk::get_movable_pos(unit); // 获取可移动位置
            for (int j = 0; j < int(arr_range.length); j++)
            {
                bool is_engaged = false;
                pk::point pos = arr_range[j];
                pk::hex @hex = pk::get_hex(pos);
                int dist_mov = pk::get_distance(unit.pos, pos);
                int dist_ref = pk::max(1, range - 1);
                if (dist_mov <= dist_ref and !hex.has_unit and !hex.has_building)
                {
                    for (int i = 0; i < 方向_末; i++)
                    {
                        pk::point neighbor_pos = pk::get_neighbor_pos(pos, i); // 搜索相邻位置
                        if (!is_engaged and pk::is_valid_pos(neighbor_pos))
                        {
                            pk::unit @unit_t = pk::get_unit(neighbor_pos);
                            if (pk::is_alive(unit_t) and unit_t.get_id() != unit.get_id() and pk::is_enemy(unit, unit_t))
                                is_engaged = true; // 如果相邻位置有敌军单位，则设置is_engaged为true
                            if (pk::is_on_fire(neighbor_pos))
                                is_engaged = true; // 排除火场位置
                        }
                    }
                    if (!is_engaged)
                        arr_evasion_pos.insertLast(pos); // 添加回避机动候选坐标
                }
            }
            if (int(arr_evasion_pos.length) == 0)
                return -1;
            // 选择离当前位置最远的位置
            arr_evasion_pos.sort(function(a, b) {
                int dist_a = pk::get_distance(a, main.unit_temp.pos);
                int dist_b = pk::get_distance(b, main.unit_temp.pos);
                if (dist_a != dist_b)
                    return (dist_a < dist_b);
                bool pos_t_a = pk::is_valid_pos(main.get_atk_target_pos(main.unit_temp, a, main.unit_max_range));
                bool pos_t_b = pk::is_valid_pos(main.get_atk_target_pos(main.unit_temp, b, main.unit_max_range));
                if (pos_t_a and !pos_t_b)
                    return true;
                if (!pos_t_a and pos_t_b)
                    return false;
                return (dist_a <= dist_b);
            });
            pk::point evasion_pos = arr_evasion_pos[0];
            return evasion_pos;
        }
        //---------------------------------------------------------------------------------------
        // 设置攻击目标为据点的函数
        pk::point set_atk_target(pk::unit @unit, pk::point evasion_pos, int max_range)
        {
            // 撤退部队无效
            if (unit.order == 部队任务_撤退)
                return -1;
            pk::hex_object @target = get_target_obj(unit, evasion_pos, max_range);
            if (pk::is_alive(target))
            {
                pk::set_order(unit, 部队任务_攻击, target.pos);
                return target.pos;
            }
            return -1;
        }
        pk::hex_object @get_target_obj(pk::unit @unit, pk::point evasion_pos, int max_range)
        {
            if (unit.weapon == 兵器_冲车)
                return null;
            pk::point pos_t = get_atk_target_pos(unit, evasion_pos, max_range);
            if (pos_t != -1 and pk::is_valid_pos(pos_t))
            {
                pk::hex_object @target = pk::get_hex_object(pos_t);
                if (pk::is_alive(target))
                    return target;
            }
            return null;
        }
        // 获取攻击目标位置的函数
        pk::point get_atk_target_pos(pk::unit @unit, pk::point evasion_pos, int max_range)
        {
            pk::point target_pos = -1;
            if (!pk::is_alive(unit))
                return -1;
            if (max_range < 1)
                return -1;
            if (unit.weapon == 兵器_冲车)
                return -1;
            pk::array<pk::point> arr_target_pos;
            pk::array<pk::point> arr_atk_range = pk::range(evasion_pos, 1, max_range);
            for (int i = 0; i < int(arr_atk_range.length); i++)
            {
                pk::point pos_t = arr_atk_range[i];
                pk::hex_object @target = pk::get_hex_object(pos_t);
                if (pk::is_alive(target) and pk::is_enemy(target, unit) and pk::get_hex_object_id(unit) != pk::get_hex_object_id(target))
                    arr_target_pos.insertLast(pos_t);
            }
            if (int(arr_target_pos.length) == 0)
                return -1;
            // 对目标进行排序
            if (int(arr_target_pos.length) > 1)
            {
                arr_target_pos.sort(function(a, b) {
                    pk::unit @unit_a = pk::get_unit(a);
                    pk::unit @unit_b = pk::get_unit(b);
                    if (pk::is_alive(unit_a) and !pk::is_alive(unit_b))
                        return true;
                    if (!pk::is_alive(unit_a) and pk::is_alive(unit_b))
                        return false;
                    if (pk::is_alive(unit_a) and pk::is_alive(unit_a))
                        return (unit_a.troops < unit_b.troops);
                    pk::building @building_a = pk::get_building(a);
                    pk::building @building_b = pk::get_building(b);
                    if (pk::is_alive(building_a) and pk::is_alive(building_b))
                        return (building_a.hp < building_b.hp);
                    return false;
                });
            }
            target_pos = arr_target_pos[0];
            return target_pos;
        }
        //---------------------------------------------------------------------------------------

        pk::building @get_siege_target_base(pk::unit @unit)
        {
            if (!pk::is_alive(unit) or !is_siege_weapon(unit.weapon))
                return null;
            int max_atk_range = get_atk_range(unit).second;
            pk::list<pk::building @> list_target_base;
            pk::array<pk::point> range = pk::get_movable_pos(unit); // 获取可移动位置
            for (int i = 0; i < int(range.length); i++)
            {
                pk::point pos = range[i];
                pk::hex @hex = pk::get_hex(pos);
                pk::array<pk::point> arr_t = pk::range(pos, 1, max_atk_range); // 获取周围位置
                for (int j = 0; j < int(arr_t.length); j++)
                {
                    pk::building @target_base = pk::get_building(arr_t[j]);
                    if (!hex.has_building and !hex.has_unit and pk::is_alive(target_base) and pk::is_enemy(unit, target_base) and target_base.get_id() < 据点_末 and !list_target_base.contains(target_base))
                    {
                        list_target_base.add(target_base);
                    }
                }
            }
            if (list_target_base.count == 0)
                return null;
            // 对目标据点进行排序
            list_target_base.sort(function(a, b) {
                bool city_a = (a.get_id() < 城市_末);
                bool city_b = (b.get_id() < 城市_末);
                if (city_a and !city_b)
                    return true;
                if (!city_a and city_b)
                    return false;
                bool gate_a = (建筑_关卡开始 <= a.get_id() and a.get_id() < 建筑_港口末);
                bool gate_b = (建筑_关卡开始 <= b.get_id() and b.get_id() < 建筑_港口末);
                if (gate_a and !gate_b)
                    return true;
                if (!gate_a and gate_b)
                    return false;
                return (a.hp < b.hp);
            });
            pk::building @target_base = list_target_base[0];
            return target_base;
        }
        //---------------------------------------------------------------------------------------
        // 判断是否为有效的攻击位置
        bool is_valid_range_atk_pos(pk::unit @src_unit, pk::point target_pos)
        {
            if (!pk::is_alive(src_unit) or !pk::is_valid_pos(target_pos))
                return false;
            pk::hex @hex = pk::get_hex(target_pos);
            if (!hex.has_unit)
                return false;
            int atk_range = get_archer_range(src_unit);
            if (pk::get_distance(src_unit.pos, target_pos) > atk_range)
                return false;
            if (hex.terrain == 지형_숲 and src_unit.weapon == 兵器_弩)
            {
                if (src_unit.has_skill(特技_射手))
                    return true;
                else
                    return false;
            }
            else
                return true;
        }
        int get_archer_range(pk::unit @src_unit)
        {
            int atk_range = 1;
            if (src_unit.weapon == 兵器_弩)
                atk_range = 2 + ((src_unit.has_tech(技巧_强弩)) ? 1 : 0);
            else if (src_unit.weapon == 兵器_战马)
                atk_range = 1 + ((src_unit.has_tech(技巧_骑射) or src_unit.has_skill(特技_白马)) ? 1 : 0);
            return atk_range;
        }
        //---------------------------------------------------------------------------------------
        // 获取部队攻击最小和最大射程的函数，根据可用战术的设置条件进行计算
        pk::int_int get_atk_range(pk::unit @unit)
        {
            pk::int_int atk_range = pk::int_int(1, 1);
            if (!pk::is_alive(unit) or unit.weapon == 兵器_剑)
                return atk_range;
            int weapon_id = unit.weapon;
            pk::equipment @epq = pk::get_equipment(unit.weapon);
            string eqp_name = pk::decode(pk::get_name(epq));
            string info = pk::format("{}", eqp_name);
            int min_range = 5;
            int max_range = 1;
            for (int j = 0; j < 전법_끝; j++)
            {
                if (epq.tactics[j])
                {
                    pk::tactics @tts = pk::get_tactics(j);
                    string tts_name = pk::decode(pk::get_name(tts));
                    info += pk::format(" {}({},{})", tts_name, tts.min_range, tts.max_range);
                    min_range = pk::min(min_range, tts.min_range);
                    max_range = pk::max(max_range, tts.max_range);
                }
            }
            if (weapon_id == 兵器_弩 and unit.has_tech(技巧_强弩))
                max_range += 1;
            if (weapon_id == 兵器_战马 and (unit.has_tech(技巧_骑射) or unit.has_skill(特技_白马)))
                max_range = pk::max(2, max_range);
            if ((weapon_id == 兵器_井阑 or weapon_id == 兵器_投石) and unit.has_skill(特技_射程))
                max_range += 1;
            atk_range = pk::int_int(min_range, max_range);
            info += pk::format(": 最小({}),最大({})", min_range, max_range);
            // if (调试模式) pk::info(info);
            return atk_range;
        }
        //=======================================================================================
        //          部队移动控制函数
        //---------------------------------------------------------------------------------------
        bool
            unit_movement_control(pk::unit @unit, pk::point evasion_pos, bool is_func262 = false)
        {
            // 撤退部队无效
            if (unit.order == 部队任务_撤退)
                return false;
            pk::hex @hex = pk::get_hex(evasion_pos);
            if (hex.has_unit or hex.has_building)
                return false;
            bool is_moved = false;
            int max_atk_range = get_atk_range(unit).second;
            int move_distance = pk::get_distance(unit.pos, evasion_pos);
            if (unit.order == 部队任务_撤退)
                return false;
            // 处理回避机动
            if (move_distance == 1) // 回避机动移动距离 = 1
            {
                // 直接移动处理回避机动
                if (pk::is_valid_pos(unit.pos) and pk::is_valid_pos(evasion_pos))
                {
                    auto evasion_path = pk::get_path(unit, unit.pos, evasion_pos);
                    if (evasion_path.length < 40 and evasion_path.length > 0)
                    {
                        pk::move(unit, evasion_path);
                        is_moved = true;
                    }
                }
            }
            else if (move_distance > 1) // 回避机动移动距离 > 1
            {
                // 备份原有部队任务信息
                int prev_order = unit.order;
                int prev_target = unit.target;
                int prev_target_type = unit.target_type;
                pk::point prev_target_pos = unit.target_pos;
                // 通过更新部队任务来控制单位回避
                if (unit.pos != evasion_pos)
                {
                    pk::set_order(unit, 部队任务_移动, evasion_pos); // 设置回避机动目的地为移动任务
                    pk::run_order(unit);
                    unit.order = prev_order;
                    unit.target = prev_target;
                    unit.target_type = prev_target_type;
                    unit.target_pos = prev_target_pos;
                    is_moved = true;
                }
            }
            if (is_moved)
            {
                // 移动处理后可攻击时攻击
                if (!unit.action_done and unit.status == 部队状态_通常 and (unit.weapon == 兵器_弩 or unit.weapon == 兵器_战马) and max_atk_range > 1)
                {
                    pk::hex_object @target = get_target_obj(unit, evasion_pos, max_atk_range);
                    if (pk::is_alive(target) and unit.troops > 2000 and unit.energy > 30)
                    {
                        pk::attack(unit, target);
                        unit.action_done = true; // 设置为部队行动完成
                    }
                }
                if (!unit.action_done and unit.weapon != 兵器_冲车 and unit.order != 部队任务_攻击)
                {
                    pk::point target_pos = set_atk_target(unit, evasion_pos, max_atk_range + (move_distance - 1)); // 更改部队任务为攻击
                    if (!is_func262 and target_pos != -1 and pk::is_valid_pos(target_pos) and pk::get_distance(target_pos, unit.pos) <= max_atk_range and is_siegerng_weapon(unit.weapon))
                    {
                        pk::run_order(unit);
                        unit.action_done = true; // 设置为部队行动完成
                    }
                }
                unit.action_done = true; // 设置为部队行动完成
                if (调试模式)
                {
                    pk::person @leader = pk::get_person(unit.leader);
                    string unit_name = (pk::is_alive(leader)) ? pk::decode(pk::get_name(leader)) : "??";
                    pk::info(pk::format("野战移动: {}({}) 移动", unit_name, get_weapon_name(unit.weapon)));
                }
            }
            return is_moved;
        }
        //=======================================================================================
        //      城市/关卡/港口 攻城战移动(攻城兵器优先移动)
        //---------------------------------------------------------------------------------------
        void func_siege_prior_atk(pk::building @dst_base, pk::force @force)
        {
            if (!pk::is_alive(dst_base) or !pk::is_normal_force(force))
                return;
            if (!pk::enemies_around(dst_base))
                return;
            string base_name = pk::decode(pk::get_name(dst_base));
            // 搜索目标据点周围的攻城部队
            get_siege_units_nearby(dst_base, force, 3); // 限制搜索距离为3
            if (list_siege_unit_around.count == 0)
                return; // 附近有攻城兵器
            pk::array<pk::unit @> arr_siege_unit = pk::list_to_array(list_siege_unit_around);
            for (int i = 0; i < int(arr_siege_unit.length); i++)
            {
                pk::unit @siege_unit = arr_siege_unit[i];
                // 撤退部队无效
                if (siege_unit.order == 部队任务_撤退)
                    return;
                if (!siege_unit.action_done)
                {
                    pk::person @leader = pk::get_person(siege_unit.leader);
                    string siege_unit_name = (pk::is_alive(leader)) ? pk::decode(pk::get_name(leader)) : "??";
                    string weapon_name = get_weapon_name(siege_unit.weapon);
                    // pk::info(pk::format("任务执行前，攻城活动: {}({}) 优先攻击 {}，已行动:{}", siege_unit_name, weapon_name, base_name, siege_unit.action_done));
                    pk::set_order(siege_unit, 部队任务_攻击, dst_base.pos);
                    pk::run_order(siege_unit);
                    siege_unit.action_done = true;
                    // pk::info(pk::format("任务执行后，攻城活动: {}({}) 优先攻击 {}，已行动:{}", siege_unit_name, weapon_name, base_name, siege_unit.action_done));
                    if (调试模式)
                    {
                        pk::info(pk::format("攻城活动: {}({}) 优先攻击 {}", siege_unit_name, weapon_name, base_name));
                    }
                }
            }
        }

        // 附近的攻城部队搜索
        pk::list<pk::unit @> list_siege_unit_around;
        void get_siege_units_nearby(pk::building @dst_base, pk::force @force, int search_range)
        {
            if (!pk::is_alive(dst_base) or dst_base.get_id() >= 据点_末)
                return;
            list_siege_unit_around.clear();
            int dist_add = (dst_base.facility == 设施_都市) ? 1 : 0;
            pk::array<pk::point> arr_range = pk::range(dst_base.pos, 1, (search_range + dist_add));
            for (int i = 0; i < int(arr_range.length); i++)
            {
                pk::point pos_t = arr_range[i];
                if (pk::is_valid_pos(pos_t) and (pk::get_building_id(pos_t) == dst_base.get_id() or pk::get_distance(pos_t, dst_base.pos) <= 4))
                {
                    pk::unit @unit = pk::get_unit(pos_t);
                    if (pk::is_alive(unit) and unit.get_force_id() == force.get_id() and !pk::is_player_controlled(unit) and !pk::is_in_water(unit) and !unit.action_done and unit.status == 部队状态_通常)
                    {
                        if (is_siege_weapon(unit.weapon) and !list_siege_unit_around.contains(unit))
                            list_siege_unit_around.add(unit);
                    }
                }
            }
        }

        // 判断部队任务的攻击目标是否为目标据点
        bool
            is_target_base(pk::unit @unit, pk::building @dst_base)
        {
            if (!pk::is_alive(unit) or !pk::is_alive(dst_base))
                return false;
            if (unit.target_type == 部队任务对象_据点)
            {
                pk::building @base_t = pk::get_building(unit.target);
                if (pk::is_alive(base_t) and base_t.get_id() == dst_base.get_id())
                    return true;
            }
            return false;
        }

        //=======================================================================================
        // 城市/关隘/港口攻城行动 (冲车/木兽, 投石/井阑攻击位置优化)
        //---------------------------------------------------------------------------------------
        void func_siege_formation(pk::building @dst_base, pk::force @force)
        {
            if (!pk::is_alive(dst_base) or !pk::is_normal_force(force))
                return;
            if (!pk::enemies_around(dst_base))
                return;
            bool cmd_1 = true;
            bool cmd_2 = true;
            int unit_count = 0;
            int push_count = 0;
            int max_count = pk::max(1, pk::min(5, 据点进攻_活动部队数));
            while (push_count < max_count and unit_count < max_count)
            {
                push_count++;
                if (cmd_1 and PushSiegeRamFormation(dst_base, force))
                    unit_count++;
                else
                    cmd_1 = false;
                if (cmd_2 and PushSiegeTwrFormation(dst_base, force))
                    unit_count++;
                else
                    cmd_2 = false;
            }
        }

        // 直接攻城兵器(冲车/木兽)攻城阵型
        bool PushSiegeRamFormation(pk::building @dst_base, pk::force @force)
        {
            // 搜索目标据点周围的部队
            get_atk_units_nearby(dst_base, force, 4); // 限制搜索范围
            if (list_siegeram_unit.count == 0)
                return false; // 周围没有攻城兵器部队
            pk::person @kunshu = pk::get_person(pk::get_kunshu_id(force));
            string force_name = pk::decode(pk::get_name(kunshu));
            string base_name = pk::decode(pk::get_name(dst_base));
            if (调试模式)
                pk::info(pk::format("攻城活动: {}→{}, 邻近攻城部队数={}, 邻近一般部队数={}", force_name, base_name, list_siegeram_unit.count, list_combat_unit_n1.count));
            // 选择攻城部队
            sort_list_siegeram_unit(); // 排序列表
            pk::unit @siege_unit = list_siegeram_unit[0];
            // 避免多次设置撤退任务
            if (siege_unit.order == 部队任务_撤退)
                return false;
            // 搜索目标据点周围的空地坐标
            int num_empty_pos = count_empty_neighbor_pos(dst_base, siege_unit, /*distance*/ 1);
            // 一线部队回避移动 (无空地坐标时)
            if (list_combat_unit_n1.count > 0 and num_empty_pos == 0)
            {
                sort_list_combat_unit_n1(); // 排序列表
                pk::unit @combat_unit = list_combat_unit_n1[0];
                pk::point dst_pos = combat_unit.pos;                                   // 保存当前坐标 (攻城部队将移动到此处)
                pk::point evasion_pos = get_evasion_pos(combat_unit, /*max_range*/ 4); // 回避移动备选坐标
                if (evasion_pos == -1 or !pk::is_valid_pos(evasion_pos))
                    return false; // 无有效坐标时无法回避移动
                string combat_unit_name = pk::decode(pk::get_name(pk::get_person(combat_unit.leader)));
                if (调试模式)
                    pk::info(pk::format("攻城活动: {} 后退坐标({},{})", combat_unit_name, evasion_pos.x, evasion_pos.y));
                bool is_moved = unit_movement_control(combat_unit, evasion_pos, /*is_func262*/ false);
                if (!is_moved)
                    return false; // 无法移动时结束
                // 重新搜索目标据点周围的空地坐标
                num_empty_pos = count_empty_neighbor_pos(dst_base, siege_unit, /*distance*/ 1);
            }
            // 攻城部队对目标据点进行攻击
            if (!siege_unit.action_done and num_empty_pos > 0)
            {
                pk::person @leader = pk::get_person(siege_unit.leader);
                string siege_unit_name = (pk::is_alive(leader)) ? pk::decode(pk::get_name(leader)) : "??";
                string weapon_name = get_weapon_name(siege_unit.weapon);
                if (调试模式)pk::info(pk::format("任务执行前，攻城活动: {}({}) 接近攻城 {}，已行动:{}", siege_unit_name, weapon_name, base_name, siege_unit.action_done));
                pk::set_order(siege_unit, 部队任务_攻击, dst_base.pos);
                pk::run_order(siege_unit);
                if (调试模式)pk::info(pk::format("任务执行后，攻城活动: {}({}) 接近攻城 {}，已行动:{}", siege_unit_name, weapon_name, base_name, siege_unit.action_done));
                siege_unit.action_done = true;
                if (调试模式)
                {
                    pk::info(pk::format("攻城活动: {}({}) {} 接近攻城", siege_unit_name, weapon_name, base_name));
                }
                return true;
            }
            return false;
        }

        // 间接攻城兵器(投石/井阑)攻城阵型
        bool PushSiegeTwrFormation(pk::building @dst_base, pk::force @force)
        {
            // 搜索目标据点周围的部队
            get_atk_units_nearby(dst_base, force, 4); // 限制搜索范围
            if (list_range_unit.count == 0)
                return false; // 周围没有间接攻城兵器部队
            pk::person @kunshu = pk::get_person(pk::get_kunshu_id(force));
            string force_name = pk::decode(pk::get_name(kunshu));
            string base_name = pk::decode(pk::get_name(dst_base));
            if (调试模式)
                pk::info(pk::format("攻城活动: {}→{}, 间接攻城部队数={}, 普通部队数={}", force_name, base_name, list_range_unit.count, list_combat_unit_n2.count));
            // 选择攻城部队
            sort_list_range_unit(); // 排序列表
            pk::unit @siege_unit = list_range_unit[0];
            // 避免多次设置撤退任务
            if (siege_unit.order == 部队任务_撤退)
                return false;
            // 搜索目标据点周围的空地坐标
            int num_empty_pos = count_empty_neighbor_pos(dst_base, siege_unit, /*distance*/ 2);
            // 二线部队回避移动
            if (list_combat_unit_n2.count > 0 and num_empty_pos == 0)
            {
                sort_list_combat_unit_n2(); // 排序列表
                pk::unit @combat_unit = list_combat_unit_n2[0];
                pk::point dst_pos = combat_unit.pos;                                   // 保存当前坐标 (攻城部队将移动到此处)
                pk::point evasion_pos = get_evasion_pos(combat_unit, /*max_range*/ 4); // 回避移动备选坐标
                if (evasion_pos == -1 or !pk::is_valid_pos(evasion_pos))
                    return false; // 无有效坐标时无法回避移动
                string combat_unit_name = pk::decode(pk::get_name(pk::get_person(combat_unit.leader)));
                if (调试模式)
                    pk::info(pk::format("攻城活动: {} 后退坐标({},{})", combat_unit_name, evasion_pos.x, evasion_pos.y));
                bool is_moved = unit_movement_control(combat_unit, evasion_pos, /*is_func262*/ false);
                if (!is_moved)
                    return false; // 无法移动时结束
                // 重新搜索目标据点周围的空地坐标
                num_empty_pos = count_empty_neighbor_pos(dst_base, siege_unit, /*distance*/ 2);
            }
            // 攻城部队对目标据点进行攻击
            if (!siege_unit.action_done and num_empty_pos > 0)
            {
                pk::set_order(siege_unit, 部队任务_攻击, dst_base.pos);
                pk::run_order(siege_unit);
                siege_unit.action_done = true;
                if (调试模式)
                {
                    pk::person @leader = pk::get_person(siege_unit.leader);
                    string siege_unit_name = (pk::is_alive(leader)) ? pk::decode(pk::get_name(leader)) : "??";
                    string weapon_name = get_weapon_name(siege_unit.weapon);
                    pk::info(pk::format("攻城活动: {}({}) 对{}执行间接攻城", siege_unit_name, weapon_name, base_name));
                }
                return true;
            }
            return false;
        }

        //---------------------------------------------------------------------------------------

        pk::list<pk::unit @> list_combat_unit_n1;
        pk::list<pk::unit @> list_combat_unit_n2;
        pk::list<pk::unit @> list_siegeram_unit;
        pk::list<pk::unit @> list_range_unit;

        // 附近的部队搜索 (必须是未行动且处于正常状态的部队，攻城部队只能是直接兵器)
        void get_atk_units_nearby(pk::building @dst_base, pk::force @force, int search_range)
        {
            if (!pk::is_alive(dst_base) or !pk::is_normal_force(force) or dst_base.get_id() >= 据点_末)
                return;
            list_combat_unit_n1.clear();
            list_combat_unit_n2.clear();
            list_siegeram_unit.clear();
            list_range_unit.clear();
            int dist_add = (dst_base.facility == 设施_都市) ? 1 : 0;
            pk::array<pk::point> arr_range = pk::range(dst_base.pos, 1, (search_range + dist_add));
            for (int i = 0; i < int(arr_range.length); i++)
            {
                pk::point pos_t = arr_range[i];
                if (pk::is_valid_pos(pos_t) and (pk::get_building_id(pos_t) == dst_base.get_id() or pk::get_distance(pos_t, dst_base.pos) <= 4))
                {
                    pk::unit @unit = pk::get_unit(pos_t);
                    if (pk::is_alive(unit) and unit.get_force_id() == force.get_id() and !pk::is_player_controlled(unit) and !pk::is_in_water(unit) and !unit.action_done and unit.status == 部队状态_通常)
                    {
                        pk::int_int unit_range = get_atk_range(unit);
                        int min_range = unit_range.first;
                        int max_range = unit_range.second;
                        int distance = pk::get_distance(unit.pos, dst_base.pos) - dist_add;
                        // 直接兵器: 冲车/木兽
                        if (is_siegeram_weapon(unit.weapon))
                        {
                            if (distance > 1 and !list_siegeram_unit.contains(unit)) // 第一线排除
                                list_siegeram_unit.add(unit);
                        }
                        // 间接兵器: 投石/井阑 (排除在射程范围内的部队)
                        if (is_siegerng_weapon(unit.weapon) or unit.weapon == 兵器_弩)
                        {
                            if (!(min_range <= distance and distance <= max_range) and !list_range_unit.contains(unit))
                                list_range_unit.add(unit);
                        }
                        // 普通部队: 枪部队
                        if (unit.weapon <= 兵器_战马)
                        {
                            if (distance == 1 and !list_combat_unit_n1.contains(unit)) // 第一线
                                list_combat_unit_n1.add(unit);
                            else if (distance == 2 and distance > max_range and !list_combat_unit_n2.contains(unit)) // 第二线
                                list_combat_unit_n2.add(unit);
                        }
                    }
                }
            }
        }

        //---------------------------------------------------------------------------------------
        // 普通战斗部队列表排序 (优先考虑枪部队，枪部队中优先考虑强力部队，近战部队中优先考虑弱小部队)
        void sort_list_combat_unit_n1()
        {
            if (list_combat_unit_n1.count <= 1)
                return;
            list_combat_unit_n1.sort(function(a, b) {
                bool skill_a = (a.has_skill(特技_工神) or a.has_skill(特技_攻城));
                bool skill_b = (b.has_skill(特技_工神) or b.has_skill(特技_攻城));
                int wpn_a = pk::get_ground_weapon_id(a);
                int wpn_b = pk::get_ground_weapon_id(b);
                if (wpn_a == 兵器_弩 and wpn_b != 兵器_弩)
                    return true;
                if (wpn_a != 兵器_弩 and wpn_b == 兵器_弩)
                    return false;
                if (wpn_a == 兵器_弩 and wpn_b == 兵器_弩)
                {
                    if (skill_a and !skill_b)
                        return true;
                    if (!skill_a and skill_b)
                        return false;
                    return (a.attr.stat[部队能力_攻击] > b.attr.stat[部队能力_攻击]);
                }
                return (a.attr.stat[部队能力_攻击] < b.attr.stat[部队能力_攻击]);
            });
        }
        // 普通战斗部队列表排序 (近战部队优先)
        void sort_list_combat_unit_n2()
        {
            if (list_combat_unit_n2.count <= 1)
                return;
            list_combat_unit_n2.sort(function(a, b) {
                int wpn_a = pk::get_ground_weapon_id(a);
                int wpn_b = pk::get_ground_weapon_id(b);
                if (wpn_a != 兵器_弩 and wpn_b != 兵器_弩)
                    return (a.attr.stat[部队能力_攻击] < b.attr.stat[部队能力_攻击]);
                if (wpn_a == 兵器_弩 and wpn_b != 兵器_弩)
                    return false;
                if (wpn_a != 兵器_弩 and wpn_b == 兵器_弩)
                    return true;
                return (a.attr.stat[部队能力_攻击] < b.attr.stat[部队能力_攻击]);
            });
        }
        // 直接兵器攻城部队列表排序 (技能优先，攻击力优先)
        void sort_list_siegeram_unit()
        {
            if (list_siegeram_unit.count <= 1)
                return;
            list_siegeram_unit.sort(function(a, b) {
                bool skill_a = (a.has_skill(特技_工神) or a.has_skill(特技_攻城));
                bool skill_b = (b.has_skill(特技_工神) or b.has_skill(特技_攻城));
                if (skill_a and !skill_b)
                    return true;
                if (!skill_a and skill_b)
                    return false;
                return (a.attr.stat[部队能力_攻击] > b.attr.stat[部队能力_攻击]);
            });
        }
        // 间接兵器部队列表排序 (攻城部队优先，技能优先，攻击力优先)
        void sort_list_range_unit()
        {
            if (list_range_unit.count <= 1)
                return;
            list_range_unit.sort(function(a, b) {
                bool siege_a = main.is_siegerng_weapon(a.weapon);
                bool siege_b = main.is_siegerng_weapon(b.weapon);
                if (siege_a and !siege_b)
                    return true;
                if (!siege_a and siege_b)
                    return false;
                bool skill_a = (a.has_skill(特技_工神) or a.has_skill(特技_攻城));
                bool skill_b = (b.has_skill(特技_工神) or b.has_skill(特技_攻城));
                if (skill_a and !skill_b)
                    return true;
                if (!skill_a and skill_b)
                    return false;
                return (a.attr.stat[部队能力_攻击] > b.attr.stat[部队能力_攻击]);
            });
        }

        //---------------------------------------------------------------------------------------

        // 计算周围空地坐标的数量
        int count_empty_neighbor_pos(pk::building @dst_base, pk::unit @unit, int distance = 1)
        {
            if (!pk::is_alive(dst_base) or !pk::is_alive(unit))
                return -1;
            int dist_add = (dst_base.facility == 设施_都市) ? 1 : 0;    // 如果目标据点是城市，增加距离1
            int dist_search = pk::max(1, pk::min(2, distance));         // 搜索距离限制在1到2之间
            pk::array<pk::point> arr_range = pk::get_movable_pos(unit); // 获取可移动的位置
            pk::array<pk::point> arr_empty_pos;                         // 存储空地坐标的数组
            for (int i = 0; i < int(arr_range.length); i++)
            {
                pk::point pos_t = arr_range[i];
                int dist_pos = pk::get_distance(pos_t, dst_base.pos) - dist_add; // 计算坐标与目标据点的距离
                pk::hex @hex = pk::get_hex(pos_t);
                if (dist_search == dist_pos and !hex.has_building and !hex.has_unit and !pk::is_water_terrain(hex.terrain)) // 距离符合条件且坐标上没有建筑或部队且不是水地形
                    arr_empty_pos.insertLast(pos_t);                                                                        // 将坐标插入空地坐标数组
            }
            if (调试模式)
                pk::info(pk::format("攻城活动: 空坐标数={}", int(arr_empty_pos.length))); // 输出空地坐标的数量
            return int(arr_empty_pos.length);                                             // 返回空地坐标的数量
        }
        //---------------------------------------------------------------------------------------

        string get_weapon_name(int weapon_id)
        {
            string weapon_name;
            switch (weapon_id)
            {
                case 兵器_剑:
                    weapon_name = "剑兵";
                    break;
                case 兵器_枪:
                    weapon_name = "枪兵";
                    break;
                case 兵器_戟:
                    weapon_name = "戟兵";
                    break;
                case 兵器_弩:
                    weapon_name = "弩兵";
                    break;
                case 兵器_战马:
                    weapon_name = "骑兵";
                    break;
                case 兵器_冲车:
                    weapon_name = "冲车";
                    break;
                case 兵器_井阑:
                    weapon_name = "井阑";
                    break;
                case 兵器_投石:
                    weapon_name = "投石";
                    break;
                case 兵器_木兽:
                    weapon_name = "木兽";
                    break;
                case 兵器_走舸:
                    weapon_name = "水军";
                    break;
                case 兵器_楼船:
                    weapon_name = "水军";
                    break;
                case 兵器_斗舰:
                    weapon_name = "水军";
                    break;
                default:
                    weapon_name = "??";
                    break;
            }
            return weapon_name;
        }

        string get_order_info(int order)
        {
            string name;
            switch (order)
            {
                case 0:
                    name = "部队任务_待命";
                    break;
                case 1:
                    name = "部队任务_移动";
                    break;
                case 2:
                    name = "部队任务_设置";
                    break;
                case 3:
                    name = "部队任务_攻击";
                    break;
                case 4:
                    name = "部队任务_撤退";
                    break;
                case 5:
                    name = "部队任务_拦截";
                    break;
                case 6:
                    name = "部队任务_护卫";
                    break;
                case 7:
                    name = "部队任务_攻城";
                    break;
                case 8:
                    name = "部队任务_修复";
                    break;
                case 9:
                    name = "部队任务_征服";
                    break;
                case 10:
                    name = "部队任务_补给";
                    break;
                case 11:
                    name = "部队任务_歼灭";
                    break;
                case 12:
                    name = "部队任务_追随";
                    break;
                case 13:
                    name = "部队任务_末";
                    break;
                default:
                    name = "部队任务_没有";
                    break;
            }

            return name;
        }

        //---------------------------------------------------------------------------------------
    };

    Main main;
}